import { EditorView } from '@codemirror/view'
import { Annotation, Compartment, TransactionSpec } from '@codemirror/state'
import { syntaxHighlighting } from '@codemirror/language'
import { classHighlighter } from './class-highlighter'

const optionsThemeConf = new Compartment()
const selectedThemeConf = new Compartment()
export const themeOptionsChange = Annotation.define<boolean>()

export type FontFamily = 'monaco' | 'lucida'
export type LineHeight = 'compact' | 'normal' | 'wide'
export type OverallTheme = '' | 'light-'

type Options = {
  fontSize: number
  fontFamily: FontFamily
  lineHeight: LineHeight
  overallTheme: OverallTheme
}

export const theme = (options: Options) => [
  baseTheme,
  staticTheme,
  /**
   * Syntax highlighting, using a highlighter which maps tags to class names.
   */
  syntaxHighlighting(classHighlighter),
  optionsThemeConf.of(createThemeFromOptions(options)),
  selectedThemeConf.of([]),
]

export const setOptionsTheme = (options: Options): TransactionSpec => {
  return {
    effects: optionsThemeConf.reconfigure(createThemeFromOptions(options)),
    annotations: themeOptionsChange.of(true),
  }
}

export const setEditorTheme = async (
  editorTheme: string
): Promise<TransactionSpec> => {
  const theme = await loadSelectedTheme(editorTheme)

  return {
    effects: selectedThemeConf.reconfigure(theme),
  }
}

const svgUrl = (content: string) =>
  `url('"),url("")',
    backgroundRepeat: 'no-repeat, repeat-x',
    backgroundPosition: 'center center, top left',
    color: 'transparent',
    border: '1px solid black',
    borderRadius: '2px',
  },
  // align the lint icons with the line numbers
  '.cm-gutter-lint .cm-gutterElement': {
    padding: '0.3em',
  },
  // reset the default style for the lint gutter error marker, which uses :before
  '.cm-lint-marker-error:before': {
    content: 'normal',
  },
  // set a new icon for the lint gutter error marker
  '.cm-lint-marker-error': {
    content: svgUrl(
      `<circle cx="20" cy="20" r="15" fill="#f87" stroke="#f43" stroke-width="6"/>`
    ),
  },
  // set a new icon for the lint gutter warning marker
  '.cm-lint-marker-warning': {
    content: svgUrl(
      `<path fill="#FCC483" stroke="#DE8014" stroke-width="6" stroke-linejoin="round" d="M20 6L37 35L3 35Z"/>`
    ),
  },
})

const loadSelectedTheme = async (editorTheme: string) => {
  if (!editorTheme) {
    editorTheme = 'textmate' // use the default theme if unset
  }

  const { theme, highlightStyle, dark } = await import(
    /* webpackChunkName: "cm6-theme" */ `../themes/cm6/${editorTheme}.json`
  )

  return [
    EditorView.theme(theme, { dark }),
    EditorView.theme(highlightStyle, { dark }),
  ]
}
